package com.client.service.impl;

import com.Emplyment.entity.QuestionBank;
import com.Emplyment.entity.QuetionCollect;
import com.Emplyment.util.CacheInterview;
import com.Emplyment.vo.QuestionBankVo;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.client.mapper.QuestionBankMapper;
import com.client.service.QuestionBankService;
import com.client.util.CompanyCallable;
import com.client.util.QuestionCallable;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class QuestionBankServiceImpl implements QuestionBankService {

    @Autowired
    private QuestionBankMapper questionBankMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    private static final String INTERVIEW_HASH_KEY = "interview:HASH:data";

    private static final String INTERVIEW_HOT_DATA = "interview:ZSET:rank";

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    @Autowired
    private ObjectMapper mapper;

    @Override
    public List<QuestionBankVo> getQuestionBank(String selectedCareer) {
        return questionBankMapper.getQuestionBank(selectedCareer);
    }

    @Override
    public Integer getCollectStatus(Integer questionId, String username) {
        return questionBankMapper.getCollectStatus(questionId, username);
    }

    /**
     * 收藏问题
     * @param
     * @param
     */
    @Override
    public void collect(QuetionCollect quetionCollect) {
        //1.在收藏表中添加用户名与问题对应的问题id
        questionBankMapper.collect(quetionCollect);
        //2.在问题表中将对应的问题的收藏值+1
        questionBankMapper.addCollectCount(quetionCollect.getQuetionbankId());

    }


    /**
     * 取消收藏问题
     * @param
     * @param
     */
    @Override
    public void cancelCollect(QuetionCollect quetionCollect) {
        //1.在收藏表中删除用户名与问题对应的问题id
        questionBankMapper.cancelCollect(quetionCollect);
        //2.在问题表中将对应的问题的收藏值-1
        questionBankMapper.cancelCollectCount(quetionCollect.getQuetionbankId());
    }

    /**
     * 获取热门面试问题信息
     * @return
     */
    @Override
    public List<QuestionBankVo> getHotQuestions() {
        List<QuestionBankVo> questionBankVoList = new ArrayList<>();
        //1、先从缓存获取
        if(Boolean.TRUE.equals(redisTemplate.hasKey(INTERVIEW_HASH_KEY)) && Boolean.TRUE.equals(redisTemplate.hasKey(INTERVIEW_HOT_DATA))){
            Set set = redisTemplate.opsForZSet().reverseRange(INTERVIEW_HOT_DATA, 0, 99);
            for (Object id : set){
                String questionId = (String) id;
                log.info("热门问题ID：{}",questionId);
                String hotQuestionsStr = (String) redisTemplate.opsForHash().get(INTERVIEW_HASH_KEY, questionId);
                CacheInterview cacheInterview = JSONObject.parseObject(hotQuestionsStr, new TypeReference<CacheInterview>() {
                });
                QuestionBank questionBank = cacheInterview.getQuestionBank();
                QuestionBankVo questionBankVo = new QuestionBankVo();
                BeanUtils.copyProperties(questionBank,questionBankVo);
                questionBankVoList.add(questionBankVo);

                //判断值是否过期
                // 1. 获取当前时间的毫秒时间戳
                long expireAt = cacheInterview.getExpireTime();
                long currentTime = System.currentTimeMillis();
                if (currentTime > expireAt) {
                    //如果当前时间大于过期时间，则过期了、加锁然后更新缓存
                    //2. 加锁
                    RLock lock = redissonClient.getLock("LOCK_QUESTION_UPDATE:" + questionId);
                    try {
                        // 尝试非阻塞获取锁（等待0秒，锁持有30秒）
                        boolean isLocked = lock.tryLock(0, 30, TimeUnit.SECONDS);
                        //TODO:线程锁释放的问题
                        if (isLocked) {
                            QuestionCallable questionCallable = new QuestionCallable(questionBankMapper,redisTemplate,Integer.getInteger(questionId));
                            FutureTask<String> futureTask = new FutureTask<>(questionCallable);
                            taskExecutor.execute(futureTask);
                        }
                    } catch (Exception e) {
                        Thread.currentThread().interrupt();
                    }finally {
                        // 确保锁在异步任务中释放
                        if (lock.isHeldByCurrentThread()) {
                            lock.unlock();
                        }
                    }
                }
            }
        }else{
            List<QuestionBank> hotQuestions = questionBankMapper.getHotQuestions();
            for (QuestionBank hotQuestion : hotQuestions){
                QuestionBankVo questionBankVo = new QuestionBankVo();
                BeanUtils.copyProperties(hotQuestion,questionBankVo);
                questionBankVoList.add(questionBankVo);

                CacheInterview cacheInterview = new CacheInterview();
                long expireTime = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(2);
                cacheInterview.setQuestionBank(hotQuestion);
                cacheInterview.setExpireTime(expireTime);

                try {
                    String cacheQuestion = mapper.writeValueAsString(cacheInterview);
                    redisTemplate.opsForHash().put(INTERVIEW_HASH_KEY,hotQuestion.getId().toString(),cacheQuestion);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
            }

        }
        return questionBankVoList;
    }

    @Override
    public List<String> getAllCareer() {
        List<String> allCareer = questionBankMapper.getAllCareer();
        return allCareer;
    }
}
